﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TicketSeller
{
    class ClusterManager
    {
        private static ClusterManager _instance = new ClusterManager();

        private  IList<ServerNode> clusterNodes = new List<ServerNode>();

        private IList<string> hasReplicationOf  = new List<string>( );

        private IList<string> replicatedAt      = new List<string>( );

        private IList<string> suspectedNodes    = new List<string>( );


        public string NodeName
        {
            set;
            get;
        }

        public IList<string> SuspectedNodes
        {
            get
            {
                return suspectedNodes;
            }
        }

        public IList<ServerNode> ClusterNodes
        {
            get
            {
                lock (clusterNodes)
                {
                    return clusterNodes;
                }
            }
        }

        public IList<string> HasReplicationOf 
        {
            get
            {
                return hasReplicationOf;
            }
        }

        public IList<string> ReplicatedAt 
        {
            get
            {
                return replicatedAt;
            }
        }

        public Boolean IsLeader { set; get; }

        private ClusterManager() 
        {
            IsLeader = false;
        }

        public static ClusterManager Instance 
        {
            get
            {
                return _instance;
            }
        }

        public ClusterManager registerNode(ServerNode serverNode)
        {
            lock (clusterNodes)
            {
                if (suspectedNodes.Contains(serverNode.Name))
                {
                    /* Need to remove all references to previously 
                     suspected node, since it could be updated */
                    Console.WriteLine( "Node {0} was previously suspected.", serverNode.Name);
                    Console.WriteLine( "All date is illiminated");
                    suspectedNodes.Remove(serverNode.Name);
                    TicketsDB.Instance.invalidateReplica(serverNode.Name);
                    hasReplicationOf.Remove( serverNode.Name);
                    replicatedAt.Remove(serverNode.Name);
                }
                // Renew node if exists (Need to update node internal data)
                Console.WriteLine( "Node {0} data is being updated", serverNode.Name);
                clusterNodes.Remove(serverNode);
                clusterNodes.Add(serverNode);
            }
            return _instance;
        }

        public ServerNode getNodeByName(string serverName)
        {
            lock (clusterNodes)
            {
                var node = ( from n in clusterNodes
                            where n.Name == serverName
                            select n).ToList().ElementAt(0);
                return node;
            }
        }

        public ClusterManager calculateSuspected( IList<ServerNode> view)
        {
            lock (clusterNodes)
            {
                foreach (String name in (from node in clusterNodes
                                         where !view.Contains(node)
                                         select node.Name).ToList<string>())
                {
                    if (suspectedNodes.Contains(name))
                        continue;
                    suspectedNodes.Add( name);
                }

                return _instance;
            }
        }

        public ClusterManager updateClusterNode(ServerNode node)
        {
            clusterNodes.Remove(node);
            clusterNodes.Add( node);
            return _instance;
        }
    }
}
